package domainfile

import (
	"fmt"

	"gorm.io/driver/clickhouse"
	"gorm.io/gorm"
	"testkjcld.bhecard.com/gitlab/kit/esim/log"
)

func NewCkDbColumnsInter(logger log.Logger) ColumnsRepo {
	return &CkDBColumnsInter{
		logger: logger,
	}
}

type CkDBColumnsInter struct {
	logger log.Logger
}

func (dc *CkDBColumnsInter) SelectColumns(dbConf *DbConfig) (Columns, error) {
	dbDsn := fmt.Sprintf("clickhouse://%s:%s@%s:%d/%s", dbConf.User, dbConf.Password, dbConf.Host, dbConf.Port, dbConf.Database)
	DB, err := gorm.Open(clickhouse.Open(dbDsn), &gorm.Config{})
	if err != nil {
		dc.logger.Errorf("connect to clickhouse err: err=%v", err)
		return nil, err
	}

	row := DB.Raw("SELECT primary_key FROM system.tables WHERE name=?", dbConf.Table).Row()
	var primaryKeyName string
	if err := row.Scan(&primaryKeyName); err != nil {
		dc.logger.Errorf("查询表主键错误: table=%s, err=%v", dbConf.Table, err)
		return nil, err
	}

	rows, err := DB.Raw(fmt.Sprintf("DESC TABLE %s", dbConf.Table)).Rows()
	if err != nil {
		dc.logger.Errorf("query clickhouse err: err=%v", err)
		return nil, err
	}
	defer rows.Close()

	var cs Columns
	for rows.Next() {
		var (
			name              string
			dtype             string
			defaultType       string
			defaultExpression string
			comment           string
			codecExpression   string
			ttlExpression     string
		)
		if err := rows.Scan(&name, &dtype, &defaultType, &defaultExpression,
			&comment, &codecExpression, &ttlExpression); err != nil {
			dc.logger.Errorf("click house scan err: err=%v", err)
			return nil, err
		}

		col := Column{
			ColumnName: name,
			DataType:   ckTypeMap(dtype),
			IsNullAble: "FALSE", // 全部默认非空
		}
		// WARNING: clickhouse 的 db2entity 必须含有ID 且为主键
		if name == primaryKeyName {
			col.ColumnKey = "PRI"
		}
		cs = append(cs, col)
	}
	return cs, nil
}

func ckTypeMap(ckType string) string {
	switch ckType {
	case "Int8", "Int16", "Int32", "UInt8", "UInt16", "UInt32":
		return "int"
	case "Int64", "UInt64":
		return "bigint"
	case "Float32":
		return "float"
	case "Float64":
		return "decimal"
	case "Decimal", "Decimal32", "Decimal64", "Decimal128":
		return "decimal"
	case "String", "FixedString", "UUID":
		return "varchar"
	case "DateTime", "DateTime64", "Date":
		return "timestamp"
	}
	return ""
}
